package pub.elephants.socket;

import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import pub.elephants.net.NetConnectionEnum;
import pub.elephants.net.annotation.ElephantsService;
import pub.elephants.net.body.ElephantsRequest;
import pub.elephants.net.body.ElephantsResponse;
import pub.elephants.net.server.ElephantsServer;
import pub.elephants.serializable.ElephantsSerializable;

import java.util.HashMap;
import java.util.Map;

/**
 * 集成spring初始化使用，初始化完成启动rpc服务
 */
public class NetServerFactory implements ApplicationContextAware, InitializingBean,DisposableBean {
    // ---------------------- server config ----------------------
    private int port = 7080;
    private int http_port = 7070;
    private NetConnectionEnum netcom = NetConnectionEnum.NETTY;
    private ElephantsSerializable serializer = ElephantsSerializable.SerializableTypeEmum.HESSIAN.serializer;
    private boolean zookeeper_switch = false;

    public void setPort(int port) {
        this.port = port;
    }
    public void setHttp_port(int http_port) {
        this.http_port = http_port;
    }
    public void setNetcom(String netcom) {
        this.netcom = NetConnectionEnum.autoMatch(netcom, NetConnectionEnum.NETTY);
    }
    public void setSerializer(String serializer) {
        this.serializer = ElephantsSerializable.SerializableTypeEmum.match(serializer, ElephantsSerializable.SerializableTypeEmum.HESSIAN).serializer;
    }
    public ElephantsSerializable getSerializer() {
        return serializer;
    }
    public void setZookeeper_switch(boolean zookeeper_switch) {
        this.zookeeper_switch = zookeeper_switch;
    }

    // ---------------------- server init ----------------------
    /**
     * init local rpc service map
     */
    private static Map<String, Object> serviceMap = new HashMap<String, Object>();
    public static ElephantsResponse invokeService(ElephantsRequest request, Object serviceBean) {
        if (serviceBean==null) {
            serviceBean = serviceMap.get(request.getClassName());
        }
        if (serviceBean == null) {
            // TODO
        }

        ElephantsResponse response = new ElephantsResponse();
        response.setRequestId(request.getRequestId());

        try {
            Class<?> serviceClass = serviceBean.getClass();
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParamTypes();
            Object[] parameters = request.getParamValues();

            /*Method method = serviceClass.getMethod(methodName, parameterTypes);
            method.setAccessible(true);
            return method.invoke(serviceBean, parameters);*/

            FastClass serviceFastClass = FastClass.create(serviceClass);
            FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);

            Object result = serviceFastMethod.invoke(serviceBean, parameters);

            response.setResult(result);
        } catch (Throwable t) {
            t.printStackTrace();
            response.setError(t);
        }finally {
            response.setSysCurrentTimeMillis(System.currentTimeMillis());
        }

        return response;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(ElephantsService.class);
        if (serviceBeanMap!=null && serviceBeanMap.size()>0) {
            for (Object serviceBean : serviceBeanMap.values()) {
                String interfaceName = serviceBean.getClass().getAnnotation(ElephantsService.class).value().getName();
                serviceMap.put(interfaceName, serviceBean);
            }
        }

    }

    private ElephantsServer server;
    private ElephantsServer httpserver;
    @Override
    public void afterPropertiesSet() throws Exception {
        // init rpc provider
        server = netcom.serverClass.newInstance();
        server.start(port, serializer);

        // init rpc-http provider
     //   httpserver = NetConnectionEnum.JETTY.serverClass.newInstance();
     //   httpserver.start(http_port, serializer);

        if (zookeeper_switch) {
      //      ZkServiceRegistry.registerServices(port, serviceMap.keySet());
        }

    }

    @Override
    public void destroy() throws Exception {
//        if (zookeeper_switch) {
//            ZkServiceRegistry.destory();
//        }

        server.destroy();
//        httpserver.destroy();
    }
}
